package com.boe.hbd.client.service.support;

import android.content.Context;
import com.boe.hbd.client.service.SensorService;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.util.Log;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;

public class SensorServiceSupport implements SensorService, SensorEventListener, Runnable {
	private static final String TAG = "SENSOR";
	
	private SensorManager sm;
	private Sensor aSensor;
	private Sensor mSensor;
	private float[] accelerometer = null;
	private float[] magneticField = null;	
	private boolean initialized = false ;

	private Boolean paused = Boolean.FALSE;
	private Thread thread = null ;
	
	private float[] lastAcc     = null;
	private float[] lastDeltaAcc= null;	 	
	private Float lastDegree    = null;
	private long lastTime       = System.currentTimeMillis();
	
	public boolean isInitialized() { 
	    return initialized;
    }

	public void initialize(Context context) {
        sm = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
        aSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		mSensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
		sm.registerListener(this, aSensor, SensorManager.SENSOR_DELAY_NORMAL);
		sm.registerListener(this, mSensor,SensorManager.SENSOR_DELAY_NORMAL); 
		thread = new Thread(this);
		thread.start();
		initialized = true ;
    }

	public void pause(Context context) { 
		sm.unregisterListener(this);
		synchronized( this ) {
			paused = Boolean.TRUE;
		}
    }

	public void resume(Context context) { 
		sm.registerListener(this, aSensor, SensorManager.SENSOR_DELAY_NORMAL);
		sm.registerListener(this, mSensor,SensorManager.SENSOR_DELAY_NORMAL);
		synchronized( this ) {
			paused = Boolean.FALSE;
		}
    }

	public void destroy(Context context) { 
		sm.unregisterListener(this);
    }

	public void onSensorChanged(SensorEvent sensorEvent) {
		synchronized( this ) {
			if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
				magneticField = sensorEvent.values.clone();
			} else if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
				accelerometer = sensorEvent.values.clone();
			}
		}
	}

	public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

	public void run() {
		while( true ) {
			synchronized( this ) {
			    if (!paused && accelerometer != null && magneticField != null ) {
		    		float[] values = new float[3];
		    		float[] R = new float[9]; 
		    		float[] I = new float[9]; 
		    		SensorManager.getRotationMatrix(R, I , accelerometer, magneticField) ;
		    		SensorManager.getOrientation(R, values);
					float degree = (float)Math.toDegrees(values[0]);
					
			    	if (lastAcc != null) {
			    		float[] deltaAcc    = new float[accelerometer.length]; 
			    		float   deltaDegree = degree - lastDegree ;
			    		boolean clockDir    = true ;
			    		
			    		if (  degree > lastDegree ) {
			    			deltaDegree = degree - lastDegree ;
							// when we moved from IV -> III e.g.: -170 -> 170
							if ( deltaDegree >= 270F ) {
								clockDir = false;
								deltaDegree = 360F + lastDegree - degree ;
							} else {
								clockDir = true ;
							}
						} else {
							deltaDegree = lastDegree - degree ;
							// when we moved from III -> IV e.g.: 170 -> -170
							if (deltaDegree >= 270F ) {
								clockDir = true ;
								deltaDegree = 360F - lastDegree + degree ;
							} else {
								clockDir = false ;
							}
						}
			    		
			    		for (int i=0 ; i<accelerometer.length; i++) {
			    			deltaAcc[i] = accelerometer[i] - lastAcc[i] ;
			    		}

			    		long time = System.currentTimeMillis() ;
			    		if (lastDeltaAcc != null && ( time - lastTime > 500 ) ) {
			    			lastTime = time ;
			    			if ( Math.abs(deltaAcc[0]) > 4.0F && Math.abs(lastDeltaAcc[0]) > Math.abs(deltaAcc[0]) && deltaAcc[0] * lastDeltaAcc[0] < 0  ) {
					    	    Log.i(TAG , "degree:[" + degree + "/" + deltaDegree + "/" + clockDir + "]" + " acc:[" + accelerometer[0] + "/" + deltaAcc[0] + "]" );
				    		}
			    		} 
			    		lastDeltaAcc   = deltaAcc    ; 
			    	}
		    		lastAcc     = accelerometer.clone(); 
		    		lastDegree  = degree   ;
			    }	
			}
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) { 
			} 
		}
	}
}
